package com.ymttest.business.data.socket;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

	public class DefaultSocketIo implements SocketIoConnection {
		 private static final Logger logger = LoggerFactory.getLogger(DefaultSocketIo.class);

		    private ConcurrentHashMap<String, ConcurrentLinkedQueue<Listener>> listeners = new ConcurrentHashMap<>();
		    
		    private String url;
		    private IO.Options options;
		    private Socket socket;
		    private String socketId;

		    public DefaultSocketIo(String url) {
		        this.url = url;
		        this.options = new IO.Options();
		        options.reconnectionAttempts = 30;
		        options.timeout = 3000;
		    }

		    
		    @Override
		    public SocketIoConnection connect() {
		        try {
		            socket = IO.socket(url, options);
		        } catch (Exception e) {
		        	 logger.info("socket连接建立成功,url:" + url);
		          //  throw new BizException("初始化socket异常, url:" + url);
		        }

		        this.listeners.forEach((event, subListeners)->{
		            for (Listener subListener : subListeners) {
		                socket.on(event, new Emitter.Listener() {
		                    @Override
		                    public void call(Object... args) {
		                        try {
									subListener.call(args);
								} catch (JSONException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
		                    }
		                    
		                });
		            }
		        });

		        //默认事件
		        socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
		            @Override
		            public void call(Object... args) {
		                logger.info("socket连接建立成功,url:" + url);
		               // socketId = CommonUtils.uuid();
		            }
		        });
		        //超出重试次数还没有连接成功，抛出重连失败事件
		        socket.on(socket.EVENT_RECONNECT_FAILED, new Emitter.Listener() {
		            @Override
		            public void call(Object... args) {
		                logger.error("socket重连失败, url:" + url);
		                try{
		                    if(socket != null){
		                        socket.close();
		                    }
		                }catch (Exception e){}

		                try{
		                    TimeUnit.SECONDS.sleep(3);
		                }catch (Exception e){}

		                connect();
		            }
		        });



		        socket.connect();

		        return this;
		    }

		    @Override
		    public void disconnect() {
		        if (socket != null) {
		            try {
		                socket.disconnect();
		            }catch (Exception e){
		                logger.error(String.format("socket disconnect exception, url:%s", url), e);
		            }
		        }
		    }

		    @Override
		    public void emit(String event, String message) {
		        if(socket != null){
		            socket.emit(event, message);
		        }else{
		        	 logger.info("socket is null, url:" + url);
		           // throw new BizException("socket is null, url:" + url);
		        }
		       // return "ok";
		    }

		    @Override
		    public boolean connected() {
		        return this.socket.connected();
		    }

		    @Override
		    public String getSocketId() {

		        return this.socketId;
		    }

		    @Override
		    public SocketIoConnection addLinstner(String event, Listener listener) {
		        ConcurrentLinkedQueue<Listener> subListeners = this.listeners.get(event);
		        if(subListeners == null){
		            subListeners = new ConcurrentLinkedQueue<>();
		            ConcurrentLinkedQueue<Listener> tempListeners = this.listeners.putIfAbsent(event, subListeners);
		            if(tempListeners != null){
		                subListeners = tempListeners;
		            }
		        }
		        subListeners.add(listener);
		        return this;
		    }
	}

